package org.dormi.learn.completablefuture;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;

/**
 * 其中supplyAsync主要用于需要返回计算结果的异步处理
 * runAsync主要用于不需要返回计算结果的异步处理
 * <p>
 * public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
 * public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor)
 * public static CompletableFuture<Void> runAsync(Runnable runnable)
 * public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor)
 * <p>
 * CompletableFuture.thenApply方法, 可以在未返回结果的情况下 定义对结果的处理, 实现了全异步
 *
 * @author : dormi330
 * @since : 22/04/18
 */
public class CompletableFutureDemo02 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main Thread =" + Thread.currentThread().getName());
        CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                System.out.println("future in Thread =" + Thread.currentThread().getName());
                timeConsuming(3000);
                int i = 10 / 0; // 开关异常
                return "hello";
            }
        });

        future.thenApply(x -> {
            System.out.println("thenApply Thread:" + Thread.currentThread().getName());
            return new MyResult(x, null);
        }).exceptionally(ex -> {
            System.out.println("exceptionally =" + Thread.currentThread().getName());
            return new MyResult(null, ex);
        }).thenApply(myResult -> {
            System.out.println("thenApply 2 Thread =" + Thread.currentThread().getName());
            return myResult;
        }).thenAccept(System.out::println);
/*
没有异常时
main Thread =main
future in Thread =ForkJoinPool.commonPool-worker-9
thenApply Thread:ForkJoinPool.commonPool-worker-9
thenApply 2 Thread =ForkJoinPool.commonPool-worker-9
MyResult{s='hello', t=null}

有异常时:
main Thread =main
future in Thread =ForkJoinPool.commonPool-worker-9
exceptionally =ForkJoinPool.commonPool-worker-9
thenApply 2 Thread =ForkJoinPool.commonPool-worker-9
MyResult{s='null', t=java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero}


JDK8中内置了一个公共线程池ForkJoinPool.commonPool()，
在没有显示设置线程池的时候，就使用的该公共线程池。
在实际上项目中，线程隔离会让计算更加高效、安全（比如不会因为线程池的不可用，导致所有依赖它的任务都得不到执行），
我们可以调用supplyAsync或runAsync带有Executor的重载方法进行设置。见Demo03

这里顺便提一下，Java8中的并行流parallelStream，
内部也是通过ForkJoinPool.commonPool()执行的，我们是无法为它指定线程池的

*/
        timeConsuming(5000);
    }

    /** 模拟耗时处理 */
    private static void timeConsuming(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static class MyResult {
        public final String s;
        public final Throwable t;

        public MyResult(String s, Throwable t) {
            this.s = s;
            this.t = t;
        }

        @Override
        public String toString() {
            return "MyResult{" +
                "s='" + s + '\'' +
                ", t=" + t +
                '}';
        }
    }
}
